﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;

namespace SemenQuest
{
    public static class ImageUtils
    {
        /// <summary>
        /// Rotates an image clockwize with a specified angle
        /// </summary>
        /// <param name="image">Image to rotate</param>
        /// <param name="angle">Angle to rotate (clockwize rotation)</param>
        /// <returns></returns>
        public static Image RotateImage(Image image, Int32 angle)
        {

            int normalizedAngle = (angle % 360);
            if (image == null)
            {
                throw new NullReferenceException("Parameter 'image' cannot be null");
            }

            //Create return image
            Int32 size = Math.Max(image.Width, image.Height);
            Bitmap returnImage = new Bitmap(size, size);

            returnImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);

            //Rotate image
            var graphics = Graphics.FromImage(returnImage);

            //graphics.DrawRectangle(
            //    new Pen(new SolidBrush((image as Bitmap).GetPixel(0, 0))), 
            //    new Rectangle(0, 0, size, size));
            float center = returnImage.Width / 2;
            graphics.TranslateTransform(center, center);
            graphics.RotateTransform(normalizedAngle);
            graphics.DrawImage(image, -image.Width / 2, -image.Height / 2);
            graphics.Dispose();

            //Remove whitespace and return
            return CropImage(returnImage);
        }

        public static Image CropImage(Image image)
        {
            if (image == null)
            {
                throw new NullReferenceException("Parameter 'image' cannot be null");
            }





            // TODO: Crop image
            return image;
        }

        /// <summary>
        /// Translate a string to a color.
        /// String must be one of the following:
        /// - Name of a color
        /// "R, G, B"
        /// "A, R, G, B"
        /// </summary>
        /// <param name="str">String to translate</param>
        /// <returns></returns>
        public static Color TranslateString(String str)
        {
            if (str.Contains(','))
            {
                List<Byte> ARGBint = new List<Byte>();
                foreach (String s in str.Replace(" ", String.Empty).Split(','))
                    ARGBint.Add(Byte.Parse(s));

                if (ARGBint.Count == 3)
                    ARGBint.Insert(0, 255);

                return Color.FromArgb(ARGBint[0], ARGBint[1], ARGBint[2], ARGBint[3]);
            }
            else
            {
                return Color.FromName(str);
            }
        }

        public static Image ChangeColor(Image image, Color oldColor, Color newColor)
        {
            return (Image)ChangeColor((Bitmap)image, oldColor, newColor);
        }
        public static Bitmap ChangeColor(Bitmap image, Color oldColor, Color newColor)
        {
            //if no change nessesary, return
            if (oldColor == newColor)
                return image;
            
            //Get bytevalues of colors
            Int32 newColorInt = newColor.ToArgb();
            Int32 oldColorInt = oldColor.ToArgb();
            Byte[] OldColorBytes = BitConverter.GetBytes(oldColorInt);
            Byte[] NewColorBytes = BitConverter.GetBytes(newColorInt);

            //Lock pixel data in memory, and make copy of pixel data
            BitmapData bmd = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, image.PixelFormat);
            Byte[] Values = new Byte[Math.Abs(bmd.Stride) * bmd.Height];
            Marshal.Copy(bmd.Scan0, Values, 0, Values.Length);

            //Cycle all pixels and change color
            Int32 Tolorance = 75;
            for (Int32 x = 0; x < Values.Length; x += 4)
            {
                if (Math.Abs(Values[x] - OldColorBytes[0]) < Tolorance &&
                    Math.Abs(Values[x+1] - OldColorBytes[1]) < Tolorance &&
                    Math.Abs(Values[x+2] - OldColorBytes[2]) < Tolorance &&
                    Math.Abs(Values[x+3] - OldColorBytes[3]) < Tolorance)
                    //Values[x] == OldColorBytes[0] &&
                    //Values[x + 1] == OldColorBytes[1] &&
                    //Values[x + 2] == OldColorBytes[2] &&
                    //Values[x + 3] == OldColorBytes[3])
                {
                    for (Int32 i = 0; i < 4; i++)
                        Values[x + i] = NewColorBytes[i];
                }
            }
            //return changed data to image, and undlock memory 
            Marshal.Copy(Values, 0, bmd.Scan0, Values.Length);
            image.UnlockBits(bmd);

            //release resources and return edited image
            Values = null;
            bmd = null;
            return image;
        }
    }
}
